Repository navigation
feat(web): review cleanup β per-area feature flags, ASPM off by default - #925
Conversation
Claude-Session: https://claude.ai/code/session_01TxtN2VcWzg6NTCLj4DbmfL Co-Authored-By: Shep Bot <shep-agent@users.noreply.github.com>
The stale good-first-issue and monthly recap watchers (spec 097) ran inside every user's daemon. They are Shep-maintainer automation, so they now run from .github/workflows/contributor-maintenance.yml through two new subcommands, `shep contributors stale-issues` and `shep contributors recap`, which reuse the existing use cases. The watcher services are deleted. The contributor view (leaderboard, contributor doctor) moves from /onboarding to /contributors, linked from CONTRIBUTING.md and not from the sidebar. /onboarding keeps only the collaboration tutorial that the supervisor and agents pages link to, and leaves the sidebar. Claude-Session: https://claude.ai/code/session_01TxtN2VcWzg6NTCLj4DbmfL Co-Authored-By: Shep Bot <shep-agent@users.noreply.github.com>
ROADMAP said ASPM ships behind a flag, but the flag defaulted to on. ASPM is a separate product category, so new installs now start with featureFlags.aspm = false (TypeSpec default, defaults factory and the web env fallback). Values users already persisted are left as they are: no migration touches feature_flag_aspm. The e2e suites that visit /aspm turn the flag on from Settings for the test and restore it afterwards. Claude-Session: https://claude.ai/code/session_01TxtN2VcWzg6NTCLj4DbmfL Co-Authored-By: Shep Bot <shep-agent@users.noreply.github.com>
Supply-chain security had its own `supplyChainSecurity` flag and overlapped ASPM. It now has no flag of its own: isSupplyChainSecurityEnabled() derives it from featureFlags.aspm, and the feature-agent pre-check, the canvas security badge, the Settings section and `shep security enforce` all use it. SHEP_SUPPLY_CHAIN_SECURITY still overrides it for CI: "false" turns it off and "true" turns it on, which Shep's own security-enforce job already sets, so the release gate keeps running on a fresh install. The field leaves TypeSpec, the defaults, the mapper and the repository SQL. The feature_flag_supply_chain_security column stays (NOT NULL DEFAULT 1) so older builds keep reading it; no data is dropped. Claude-Session: https://claude.ai/code/session_01TxtN2VcWzg6NTCLj4DbmfL Co-Authored-By: Shep Bot <shep-agent@users.noreply.github.com>
Nothing read `system.autoUpdate`, so it leaves TypeSpec, the defaults and the mapper. Its sys_auto_update column is NOT NULL with no default, so the mapper keeps writing 1 (the old default) and never reads it; older builds still see their usual value. The Aider and Continue agent types were "coming soon" placeholders with no executor. They leave the AgentType enum, the agent catalog, the canvas icons, the TUI picker translations and the stories. A settings row that still holds either value reads back as the default agent, so no data is rewritten. Claude-Session: https://claude.ai/code/session_01TxtN2VcWzg6NTCLj4DbmfL Co-Authored-By: Shep Bot <shep-agent@users.noreply.github.com>
Specs 120β132 shipped with no flag. Each software-factory area now has one, default on so nothing changes for users: spaces, trackers, knowledge, signals, opportunities, feedback, discovery, incidents, outcomes, docsFirst, autopilot and factory (TypeSpec, migration 166 with DEFAULT 1, mapper, repository SQL, defaults, web flag state). Each flag gates its area: sidebar entries, pages (requireFeaturePage), POST /api/feedback and /api/alerts (404 while off), CLI groups (gateByFeatureFlag hides the group and says how to turn it on; shep aspm now uses it too), the daemon's sync, discovery, outcome and autopilot passes (checked on every pass), and the docs-first planning instructions and merge gate. A domain catalog gives every flag a group and a one-line description. ListFeatureFlagsUseCase and SetFeatureFlagUseCase serve both /settings/feature-flags (every flag, its default and a switch; linked from Settings) and `shep settings flags [enable|disable <flag>]`. The Settings page's Feature Flags section renders the same catalog-driven list instead of hand-written rows, which also adds the missing githubImport switch. Claude-Session: https://claude.ai/code/session_01TxtN2VcWzg6NTCLj4DbmfL Co-Authored-By: Shep Bot <shep-agent@users.noreply.github.com>
Cloudflare Pages was the only cloud deploy provider that worked. Vercel, Netlify, AWS Amplify and GCP Cloud Run were stubs listed as "Coming soon" that threw on connect and deploy. This removes them. Cloudflare Pages works as before. - TypeSpec: CloudDeploymentProvider keeps only CloudflarePages (output.ts and apis/json-schema regenerated) - core: delete the four *.provider.stub.ts files, base-provider-stub.ts, their DI registrations and ProviderNotImplementedError; drop `enabled` from ICloudDeploymentProvider, the registry descriptor and ListCloudProvidersUseCase - the registry now lists only ids that have an adapter, and resolves them from the container it was registered in rather than the global root - add domain parseCloudDeploymentProvider, replacing four copies of parseProvider in the CLI commands and web routes - CLI: `shep app cloud-providers ls/connect` lose the coming-soon output - web: drop the "Coming soon" rows, disabled states and removed brand icons from ProviderList, ProviderDropdown, DeployPanel, DeployButton, SmartDeployCluster and ConnectProviderModal; share labels and the list entry type in cloud-providers.ts; update stories, add ProviderList and CloudProviderIcons stories Persisted values: connect rejected the stubs, so no cloud_provider_tokens row can hold one, but `select-provider` and `shep app deploy start --provider` could store a stub id in applications.cloud_deployment_provider. No migration rewrites data. The application mapper reads an unknown provider id as no selection, so deploy falls back to the first connected provider. Token listing skips unknown ids too. Claude-Session: https://claude.ai/code/session_01TxtN2VcWzg6NTCLj4DbmfL Co-Authored-By: Shep Bot <shep-agent@users.noreply.github.com>
Co-Authored-By: Shep Bot <shep-agent@users.noreply.github.com>
Specs 133 and 134 are taken by the telemetry and unified-decisions workstreams. Comments and test names that cite the spec follow the new number. Co-Authored-By: Shep Bot <shep-agent@users.noreply.github.com>
The view's group headings jumped from h1 to h3; they are h2 on the page and stay h3 inside the Settings section. The phone navigation test opens the ASPM Security group, so it turns the aspm flag on first now that it defaults to off. Co-Authored-By: Shep Bot <shep-agent@users.noreply.github.com>
git 2.56 on the Windows runner rejects GIT_CONFIG_GLOBAL=NUL, so every harness real-git test failed in git init. Git for Windows maps /dev/null to its null device, as the merge-step real-git tests already rely on. Co-Authored-By: Shep Bot <shep-agent@users.noreply.github.com>
|
Unit Tests (windows-latest) failed on The cause is not this PR's code. The Windows runner now has git 2.56.0, which rejects
Generated by Claude Code |
|
Unit Tests (windows-latest) failed on I don't think this PR causes it. The PR does not touch the terminal service or that test, and the same unit step passed on Windows on the previous commit ( I tried to re-run the failed job and got a 403, because this integration cannot re-run workflows. Could someone with access re-run "Unit Tests (windows-latest)"? If it keeps happening, my proposed fix (not applied here, to keep this PR's scope) is to make that test's teardown tolerate a lingering ConPTY handle on Windows. The temp directory lives under the OS temp folder and does not affect any assertion: } finally {
try {
removeDirWithRetry(tempDir);
} catch (error) {
// Windows: conhost can outlive the shell and keep tempDir open.
if (process.platform !== 'win32' || (error as NodeJS.ErrnoException).code !== 'EBUSY') throw error;
}
}Generated by Claude Code |
On Windows the conhost.exe that node-pty starts with the shell inherits its cwd and can outlive the shell's exit event, so the pty test's teardown failed with EBUSY even after waiting for exit and retrying. The test now leaves that temp dir to the OS on that one Windows error; any other error still fails it. Co-Authored-By: Shep Bot <shep-agent@users.noreply.github.com>
|
Unit Tests (windows-latest) failed again on No test in this PR's diff ran before the service died, and the terminal test fixed in This needs a re-run of Unit Tests (windows-latest). This integration gets a 403 when it tries to re-run workflows, so could someone with access re-run it? If esbuild dies again, it is reproducible and I will dig into what is taking the transform service down. Generated by Claude Code |
|
I looked into whether this PR causes the esbuild crash in Unit Tests (windows-latest) on
I conclude that the esbuild service on the runner died in the middle of the run, and that nothing in this PR caused it. A re-run of Unit Tests (windows-latest) should confirm it: https://github.com/shep-ai/shep/actions/runs/37937489099. This integration cannot re-run it (403). If it fails the same way again, it is reproducible and I will chase it. Generated by Claude Code |
β¦up-cuts Renumber the software-factory feature-flag migration from 166 to 169: main's 166 is add-agent-question-decision, and #924 and telemetry hold 167 and 168. Take main's empty-file git config isolation in the test harness and keep both sides' LESSONS entries. Claude-Session: https://claude.ai/code/session_01TxtN2VcWzg6NTCLj4DbmfL Co-Authored-By: Shep Bot <shep-agent@users.noreply.github.com>
## What Adds `docs/competitors/t3code.md`, a product and architecture review of T3 Code (pingdotgg/t3code) compared with Shep, and links it from `docs/competitors/README.md`. The doc covers four topics: - **What to adopt:** the inline-options decision pattern, plan capture, hidden-ref checkpoints and capability records. - **What to skip.** - **What to cut or consolidate in Shep.** - **A telemetry design.** It ends with the owner's decision on every recommendation. ## Why This is the record behind the follow-up work: - spec 133 metrics (#923) - spec 134 unified decisions (#922, #924) - spec 135 cleanup (#925) - the Effect-TS evaluation issue (#921) ## Screenshots / Recording N/A β non-UI change. ## Testing Docs only. Markdown is excluded from Prettier (`*.md` in `.prettierignore`). I checked the claims in the doc against `main@0304cfc` and `pingdotgg/t3code@a4c9494b`. ## Checklist - [x] Commit messages follow [Conventional Commits](https://www.conventionalcommits.org/) β `docs`, so no release π€ Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01SGhpsQ4T9PshbZFxzCQQMy --- _Generated by [Claude Code](https://claude.ai/code/session_01SGhpsQ4T9PshbZFxzCQQMy)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
β¦up-cuts Co-Authored-By: Shep Bot <shep-agent@users.noreply.github.com>
The spec waited for the first server-action response on /settings and then on response.finished(). The page fires other actions on load, and a server action's response streams the re-rendered page, so finished() hung for 60s in CI. Match the save by its preferredLanguage body and rely on the reload check instead. Claude-Session: https://claude.ai/code/session_01TxtN2VcWzg6NTCLj4DbmfL Co-Authored-By: Shep Bot <shep-agent@users.noreply.github.com>
β¦up-cuts Bring in telemetry (#923, migration 168); the feature-flag migration stays at 169. Take main's settings-rows extraction and stories, keeping the row's flex basis so switches stay beside long descriptions. Keep the i18n spec's save-matching without response.finished(), which hung in CI. Claude-Session: https://claude.ai/code/session_01TxtN2VcWzg6NTCLj4DbmfL Co-Authored-By: Shep Bot <shep-agent@users.noreply.github.com>
135 belongs to the review-cleanup spec in #925. Claude-Session: https://claude.ai/code/session_014Zwb23kb4xTBxJtqc2hKbU Co-Authored-By: Shep Bot <shep-agent@users.noreply.github.com>
<p align="center"> <a href="https://github.com/shep-ai/shep"> <img src="https://raw.githubusercontent.com/shep-ai/shep/main/docs/screenshots/shep-card.jpg" alt="Shep β run multiple AI agents in parallel" width="720" /> </a> </p> # π Shep [v1.240.0](/compare/v1.239.0...v1.240.0) Β· _2026-10-11_ > Your organization does not have access to Claude. Please login again or contact your administrator. ### β¨ Features * **web:** review cleanup β per-area feature flags, ASPM off by default ([#925](#925)) ([58df74f](58df74f)), closes [#923](#923) [922/#924](#924)     ## π¦ Install or update ```bash # upgrade an existing install npm i -g @shepai/cli@1.240.0 # or run instantly without installing npx @shepai/cli@latest ``` ## π¬ Join the community [π¬ **Discord**](https://discord.gg/ES6tdVFfur) Β· [π **Docs**](https://github.com/shep-ai/shep#readme) Β· [β **Star on GitHub**](https://github.com/shep-ai/shep) Β· [π **Report an issue**](https://github.com/shep-ai/shep/issues) --- <sub>π€ Released autonomously by Shep β built by parallel AI agents working in isolated git worktrees. Try it: `npx @shepai/cli`</sub> Co-Authored-By: Shep Bot <shep-agent@users.noreply.github.com>
β¦ (spec 136) (#929) ## What This is the telemetry follow-up noted in #922 and #924. Every recorded answer to an agent decision now emits `decision.answered`, and a background agent's question that reaches its deadline emits the new `decision.defaulted` event. Both go through the `ITelemetry` port from #923. | Event | Properties | Recorded by | | ----- | ---------- | ----------- | | `decision.answered` | `kind` (`DecisionKind`), `surface` (new `DecisionSurface`: web / cli / chat / supervisor / other), `latency` (bucket from asked to answered), `pickedRecommended` | `AnswerAgentQuestionUseCase`, once per answer it actually records | | `decision.defaulted` | `kind`, `timeout` (bucket of the deadline the agent set) | `AskAgentDecisionUseCase`, when its deadline settle wins | ## Why Spec 133 defined `decision.answered` but did not emit it, and its `kind` and `surface` were raw strings. The T3 Code review asks three things that need data: whether people answer agent questions, where they answer them, and whether they take the recommendation. It also asks how often agents proceed on their own at the deadline. - **Emit points:** each event is emitted right after the use case's atomic `settlePending` succeeds. Each decision is therefore counted exactly once without an `onceKey`. A lost race (CLI vs web), a refused answer, or agent questions being off records nothing. A person answering at the deadline records an answer, not a default. - **Surface:** each caller passes its own surface: the web action (`web`, which overrides anything the client sends), the CLI (`cli`), the chat bridge (`chat`) and the supervisor router (`supervisor`). Nothing parses the free-form `answeredBy` actor. - **Typing:** in the property map, `kind` and `surface` are now enums. That makes the compiler reject a content property at every emit site. - **Refactor while touching the file:** the `AskAgentDecisionOutcome` string union is now the `DecisionOutcome` enum, with a new `Disabled` member. The MCP tool's wire values are unchanged. Stored questions use `RecordedDecisionOutcome`, which excludes `Disabled`, so the activity log needs no UI for a state it can never show. - **Docs:** `docs/telemetry.md` lists both events. Spec: `specs/136-decision-telemetry/`. It was renumbered from 135, which belongs to #925; the branch name still says 135. ## Screenshots / Recording No UI changes. ## Testing - `answer-agent-question.use-case.test.ts`: - Properties for a decision answered on the web, including the latency bucket with a faked clock and `pickedRecommended: true`. - Typed text counts as not the recommendation. - A legacy question is reported as `Legacy`, with `Other` as the default surface. - Answering twice records one event. - Agent questions off, or a refused answer, records nothing. - `ask-agent-decision.use-case.test.ts`: - The deadline default records `decision.defaulted` with the timeout bucket. - A person answering at the deadline records no default. - Cancelled and disabled outcomes record no default. - Caller tests assert the surface they pass: web action, CLI `answer` (with `--answer` and interactive), chat bridge, supervisor router. Ran locally: `pnpm lint`, `format:check`, `check:stories`, `typecheck`, `test:unit` (14864 passed), `test:int` (2132 passed), `build`, `build:web`, `build:storybook`, and `generate` with a clean diff. After the renumbering: lint, format:check, typecheck and the affected test files. ## Checklist - [x] `pnpm lint` passes - [x] `pnpm format:check` passes - [x] `pnpm typecheck` passes - [x] `pnpm test:unit` and `pnpm test:int` pass - [x] `pnpm build` succeeds - [x] (Domain changes) `pnpm tsp:compile` ran and `packages/core/src/domain/generated/output.ts` is committed - [x] Tests landed RED-first per the TDD guide - [x] No `domain/` or `application/` file imports anything from `infrastructure/` - [x] Commit messages follow Conventional Commits π€ Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_014Zwb23kb4xTBxJtqc2hKbU --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Shep Bot <shep-agent@users.noreply.github.com>
## What `ITerminalSessionService.close()` now returns a promise that resolves once the session's processes have exited. It kills the pty and waits for the exit event, with a time limit. On Windows it then terminates the shell and its ConPTY host (`conhost.exe` / `OpenConsole.exe`) by their **captured PIDs** if either is still running. `DELETE /api/terminal/:id` waits for this to finish. - **New `ConptyHostReaper`** (`infrastructure/services/terminal/conpty-host-reaper.ts`): - When a terminal is created, it asks Windows for the shell's console host (`NtQueryInformationProcess(ProcessConsoleHostProcess)`). The query has to run while the shell is alive. - Before killing anything, it checks with `tasklist` that the PID still has the image it had when captured. A recycled PID is never killed, and no process is ever matched by name. - **Host reaped on natural exit too:** when the shell exits by itself (`exit`), the host is also terminated if it survives. - **cwd validation moved:** it now lives in `terminal-cwd.ts`, which keeps the service at about 300 lines. ## Why Closes #927. I probed node-pty 1.1.0 on windows-2022 (two CI rounds on this PR, using a temporary Windows-only probe that is now deleted): | Case | Result | | --- | --- | | Closed right after `create()` | `cmd.exe` and `conhost.exe` both stayed alive for about 0.7 s. The cwd was `EBUSY` that whole time. The exit event arrived after about 650 ms. | | Closed once the shell was ready | Both processes exited within about 10 ms. | | `useConptyDll: true` | `OpenConsole.exe` was still running seconds after the exit event. | The host's parent is our own process, not the shell, so waiting for the shell alone does not cover it. **node-pty upgrade:** not done. 1.1.0 is still the latest stable release and already has `useConptyDll`, which made the leak worse in the probe. The 1.2.0 releases are all betas. ## Screenshots / Recording N/A β non-UI change. ## Testing **New tests:** - **Windows only:** after `await close()`, no process the session started is still alive, and its cwd can be removed with no retries. This runs once closing right after create and once after the shell is ready. - **All platforms:** `close()` resolves only after the shell's exit listeners have fired. - **All platforms:** closing an unknown session is a no-op. - **`ConptyHostReaper`:** output parsing; never kills a PID whose image changed; handles a process that already exited; terminates a survivor (Windows). The first-round RED test passed on Windows because an immediate `rmSync` is a timing-dependent signal. That is why the assertion is now on the processes themselves; LESSONS.md explains this. The all-platform close test failed before the fix on Linux. **Local runs on the merged head:** | Check | Result | | --- | --- | | `pnpm lint`, `pnpm format:check` | pass | | `pnpm typecheck`, `pnpm typecheck:web` | pass | | `pnpm test:unit` | 14,935 passed | | `pnpm test:int` | 2,139 passed | | `pnpm build` | pass | The Windows behaviour is verified only by the `Unit Tests (windows-latest)` job. ## Notes for the reviewer - **#925 workaround removed:** the `removeShellCwd` EBUSY workaround from #925 is gone. The test now awaits `close()` and removes the directory normally. - **Cost per terminal on Windows:** the host capture launches one PowerShell process per terminal opened, and compiling the P/Invoke shim takes about 2.5 s. It runs in the background. `close()` waits for it only when a terminal is closed within those first seconds. ## Checklist - [x] `pnpm lint` passes - [x] `pnpm format:check` passes - [x] `pnpm typecheck` passes - [x] `pnpm test:unit` and `pnpm test:int` pass - [x] `pnpm build` succeeds - [x] No `domain/` or `application/` file imports from `infrastructure/` - [x] Conventional Commits; `fix` for the user-visible change - [x] Updated LESSONS.md π€ Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01Kqkw9jhaERENoT56mDS7ZR --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Shep Bot <shep-agent@users.noreply.github.com>
β¦932) ## What Adds an `sdlcBoard` feature flag, **off by default**, and puts the SDLC board behind it. While the flag is off: - the sidebar hides the **SDLC Board** link; - `/sdlc` returns 404; - `GET /api/sdlc-events` returns 404; - `listSdlcBoard`, `reorderSdlcTask`, `updateSdlcTaskStatus` and `updateSdlcSubTaskStatus` return an error without calling their use cases. The flag is in the feature-flag catalog under **Platform**. It is listed on `/settings/feature-flags` with a switch, and `shep settings flags enable sdlcBoard` turns it on from the CLI. While it is on, everything works as before. Unchanged: the Control Center canvas, the `/features` table, and the agent-side board tracker. The tracker keeps recording tasks, so turning the flag on shows a complete board. The board has no CLI command group, so there is no CLI gate to add. | Commit | Change | | --- | --- | | `19edf55` | The flag: TypeSpec (`= false`), defaults, migration **171** (`feature_flag_sdlc_board INTEGER NOT NULL DEFAULT 0`), mapper, repository SQL, web flag state, catalog entry, and labels in all 9 locales | | `777699b` | One shared web feature gate in `lib/feature-gate.ts` (`isFeatureOn`, `featureNotFound`, `FEATURE_OFF_ERROR`). `requireFeaturePage` and the feedback/alerts routes now use it; `intakeDisabled()` is removed | | `6227dca` | Gates the sidebar link, the page, the SSE route and the four actions | | `50e73f2` | The `/sdlc` accessibility e2e case turns the flag on; FEATURES, domain-models and the LESSONS flag checklist are updated | | `05e4558` | Migration renumbered from 170 to 171 (170 is the checkpoints workstream's) | ## Why The owner decided the SDLC board should not be part of the default product surface. Implements `specs/140-sdlc-board-flag/`, building on the flag catalog and `/settings/feature-flags` from #925 (spec 135). ## Screenshots / Recording There is no new component. The flags view renders the new row from the catalog, like every other flag. The web e2e suite ran locally against the release build; it covers `/settings/feature-flags`, plus `/sdlc` with the flag on. ## Testing Local runs: | Check | Result | | --- | --- | | `pnpm generate` | no drift | | `pnpm lint`, `pnpm format:check`, `pnpm typecheck`, `pnpm tsp:compile` | pass | | `pnpm test:unit` | 14,953 passed (on the merge with `main` at `1e1f859`) | | `pnpm test:int` | 2,142 passed | | `pnpm check:stories` | pass | | `pnpm build:release`, `pnpm build:storybook` | pass | | Web e2e with CI settings (flaky counts as failure) | 86 of 86 passed | New tests, each landed RED first: - `tests/unit/presentation/web/app/sdlc-board-gating.test.ts` covers the page, the SSE route and all four actions, with the flag off and on. - `tests/unit/presentation/web/lib/feature-gate.test.ts`. - A sidebar-links case for `/sdlc`. - `migration-171-sdlc-board-flag.test.ts`, which checks the column, `DEFAULT 0` and idempotency. - A settings repository round-trip. - The mapper both ways, the catalog group and the defaults. ## Checklist - [x] `pnpm lint` passes - [x] `pnpm format:check` passes - [x] `pnpm typecheck` passes - [x] `pnpm test:unit` and `pnpm test:int` pass - [x] `pnpm build` succeeds - [x] `pnpm build:storybook` succeeds (no new components) - [x] `pnpm tsp:compile` ran and `packages/core/src/domain/generated/output.ts` is committed - [x] Tests landed RED-first - [x] No `domain/` or `application/` file imports anything from `infrastructure/` - [x] Conventional Commits; `feat` for the user-visible change - [x] LESSONS.md: the flag checklist now names the shared gate, and says that API routes and server actions need the gate too, not just the page π€ Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01TxtN2VcWzg6NTCLj4DbmfL --- _Generated by [Claude Code](https://claude.ai/code/session_01TxtN2VcWzg6NTCLj4DbmfL)_ --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Shep Bot <shep-agent@users.noreply.github.com>
#931) ## What After every feature-agent step that can change files, Shep now snapshots the feature's worktree into a hidden ref, `refs/shep/checkpoints/<featureId>/<seq>-<node>`, and records it in SQLite. Users can then: - see what each step changed, - diff any two steps, - roll the worktree back to a step, from the CLI or from a new **Checkpoints** tab in the feature drawer. ## Why Implements `specs/138-git-checkpoints/`: workstream T4 of the T3 Code review (`docs/competitors/t3code.md`, "What Shep Should Take" Β§3). Until now a run kept only its end state, the branch. Nobody could answer "what did *implement* change, and what did *repair* change after it?", or undo one bad step without editing git by hand. **Capture** Capture follows T3's approach and never touches the user's branch, HEAD, index or files: 1. Seed a temporary `GIT_INDEX_FILE`. 2. `add -A`, then `write-tree`. 3. `commit-tree` with a fixed identity and no signing, then `update-ref`. All writes run with `core.fsync=objects,reference`. - **Where it hooks in.** A `withCheckpoint` wrapper covers every file-changing node of the full, fast and exploration graphs. - **Baseline.** A baseline is captured before the first step. - **Unchanged steps.** A step that changed nothing records nothing. - **Failures.** A capture failure is logged and never fails the run. **Diff** Diffs run `git diff` between two checkpoint commits and are cached in-process. The unified-diff parser previously in `GitPrService` (with a hand copy in the GitHub review service) is now one shared module. **Restore** Restore first captures a `pre-restore` checkpoint, so a restore can itself be undone. It then runs `clean -fd`, `read-tree --reset -u` and `reset -q`. The working tree matches the checkpoint, ignored files are kept, and the branch is not moved, so nothing already pushed is rewritten. A single `CheckpointRestorePolicy` gates restore, and the list exposes its answer as a typed `CheckpointRestoreBlocker`. It refuses unless all three hold: - the feature has its own worktree, distinct from the repository path; - git confirms the directory is a linked worktree; - the latest agent run is not pending or running. **Cleanup** Refs and rows are deleted when the worktree is removed (post-merge cleanup, delete) or the feature is archived (manual or auto-archive). **Data model** - New TypeSpec entity `GitCheckpoint`. - Enums `GitCheckpointKind` and `CheckpointRestoreBlocker`. - Migration **170** `git_checkpoints`. 169 belongs to #925, which is merged into this branch. ## Screenshots / Recording Storybook (`Features/Checkpoints/*`) with fixture data. Light and dark. | | Light | Dark | | --- | --- | --- | | Per-step diff |  |  | | Compare two steps |  |  | | Restore blocked (agent running) |  |  | | Restore confirmation |  |  | ## Testing **Real git** (global/system config isolated, signing off, worktree path with a space): `tests/integration/infrastructure/services/git/git-checkpoint.service.test.ts` - Capture leaves `git status`, HEAD, branch and index unchanged. - Untracked files are captured; ignored files are not. - The ref is visible from the main checkout. - Diff and stat work, and the cache returns the same object. - Restore equals the checkpoint, keeps ignored files and leaves the branch alone. - Linked worktree vs main checkout is detected. - Ref deletion removes only the feature's refs. - The unborn-branch case works. - A directory that is not the top of its own work tree is refused, e.g. a leftover worktree directory inside another repository after post-merge cleanup, so the parent checkout is never snapshotted. - A mutation check passed: without `GIT_INDEX_FILE` the "index untouched" test goes red. **Repository:** `tests/integration/infrastructure/repositories/sqlite-git-checkpoint.repository.test.ts` (non-default round-trip, UNIQUE per feature, delete, idempotent migration). **Use cases** (`tests/unit/application/use-cases/features/checkpoints/`) - Baseline and step numbering; unchanged tree skipped. - Per-step and two-step diffs. - Every restore refusal; Windows-spelled repository path treated as the same checkout. - Best-effort delete. **Pipeline:** `with-checkpoint.test.ts` and `checkpoint-capture.test.ts`, plus graph-level tests asserting which nodes capture in the full, fast and exploration graphs (validate nodes never capture). **Cleanup hooks:** archive, auto-archive watcher, worktree cleanup, delete. **CLI:** `checkpoints.command.test.ts`. **Web:** `checkpoints-tab.test.tsx` (per-step, baseline, compare, restore confirm/refusal, blocker, empty, error), plus drawer tab visibility. **DI:** the bootstrap test resolves every new token and goes red without the registration. **Storybook:** `CheckpointList` (Default / RestoreDisabled / WithPreRestore / WithoutRestore), `CheckpointCompareBar`, `CheckpointRestoreDialog` (Default / Pending / Closed), `CheckpointsTab`. Local results, on the tree merged with `main`: - `lint`, `format:check`, `typecheck`, `check:stories` and `generate` (no drift) all pass. - `test:unit`: 15,043 passed. - `test:int`: 2,160 passed. The first run had 7 failures in `dependency-path-traversal`, caused by the unpatched `extract-zip` I had installed into the sandbox as a stand-in; with the repo patch applied, all pass. - `build`, `build:web` and `build:storybook` pass. ## Checklist - [x] `pnpm lint` passes - [x] `pnpm format:check` passes - [x] `pnpm typecheck` passes - [x] `pnpm test:unit` and `pnpm test:int` pass - [x] `pnpm build` succeeds - [x] (UI only) `pnpm build:storybook` and `pnpm build:web` succeed; every new component has a colocated `.stories.tsx` - [x] (Domain changes) `pnpm generate` ran and `output.ts` plus `apis/json-schema/` are committed - [x] (New use case) Tests landed RED-first per the TDD guide - [x] No `domain/` or `application/` file imports anything from `infrastructure/` - [x] Commit messages follow Conventional Commits - [x] Updated LESSONS.md π€ Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01V37fpj6cexvgoExiG9SHKj --- _Generated by [Claude Code](https://claude.ai/code/session_01V37fpj6cexvgoExiG9SHKj)_ --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Shep Bot <shep-agent@users.noreply.github.com>
<p align="center"> <a href="https://github.com/shep-ai/shep"> <img src="https://raw.githubusercontent.com/shep-ai/shep/main/docs/screenshots/shep-card.jpg" alt="Shep β run multiple AI agents in parallel" width="720" /> </a> </p> # π Shep [v1.241.0](/compare/v1.240.0...v1.241.0) Β· _2026-10-11_ > Your organization does not have access to Claude. Please login again or contact your administrator. ### β¨ Features * **agents:** emit decision.answered and decision.defaulted telemetry (spec 136) ([#929](#929)) ([1e1f859](1e1f859)), closes [#922](#922) [#925](#925)     * **agents:** git checkpoints after each feature-agent step (spec 138) ([#931](#931)) ([26265ed](26265ed)), closes [#925](#925)     * **web:** put the SDLC board behind a feature flag, off by default ([#932](#932)) ([e71f138](e71f138)), closes [#925](#925) ### π Bug Fixes * **cli:** wait for the conpty host to exit when a terminal closes ([#928](#928)) ([94a846d](94a846d)), closes [#925](#925) [#925](#925) ## π¦ Install or update ```bash # upgrade an existing install npm i -g @shepai/cli@1.241.0 # or run instantly without installing npx @shepai/cli@latest ``` ## π¬ Join the community [π¬ **Discord**](https://discord.gg/ES6tdVFfur) Β· [π **Docs**](https://github.com/shep-ai/shep#readme) Β· [β **Star on GitHub**](https://github.com/shep-ai/shep) Β· [π **Report an issue**](https://github.com/shep-ai/shep/issues) --- <sub>π€ Released autonomously by Shep β built by parallel AI agents working in isolated git worktrees. Try it: `npx @shepai/cli`</sub> Co-Authored-By: Shep Bot <shep-agent@users.noreply.github.com>
What
This is the cleanup PR from the T3 Code product review. It covers the items the owner agreed to, with one commit per item:
bb81a67_serve,shep ui,dev:web). They now run from the new scheduled workflow.github/workflows/contributor-maintenance.yml, through two new commands,shep contributors stale-issuesandshep contributors recap. Both reuse the existing use cases. The watcher services are deleted. The contributor view (leaderboard, contributor doctor) moves to/contributors, which is linked from CONTRIBUTING.md and not from the sidebar./onboardingkeeps only the collaboration tutorial and leaves the sidebar.2810b71featureFlags.aspmnow defaults tofalsein TypeSpec, the defaults factory and the web env fallback. Values users already saved are kept; no migration touches them. ROADMAP.md is updated to match. The e2e tests that visit/aspmturn the flag on for the test and back off afterwards.0b9221fsupplyChainSecurityflag is gone, and every surface followsaspmthroughisSupplyChainSecurityEnabled(): the feature-agent pre-check, the canvas badge, the Settings section andshep security enforce.SHEP_SUPPLY_CHAIN_SECURITYstill overrides the flag in either direction. Shep's ownsecurity-enforceCI job already sets it totrue, so the release gate keeps running. Thefeature_flag_supply_chain_securitycolumn stays and is no longer read.d3a2157system.autoUpdateand the placeholder agent typesaiderandcontinue. Thesys_auto_updatecolumn is NOT NULL with no default, so it is still written as1but never read. A settings row that still holdsaiderorcontinuereads back as the default agent.agentQuestionBridge,AgentQuestionExecutorBridgeandInteractionBubbleare untouched.ef9c9aespaces,trackers,knowledge,signals,opportunities,feedback,discovery,incidents,outcomes,docsFirst,autopilot,factory. They are stored in migration 169 (DEFAULT 1). Each flag gates its area's nav entry, pages, intake API, CLI group, daemon loop and, fordocsFirst, the docs gate. A new view at/settings/feature-flagslists every flag with a one-line description, its default and an on/off switch; Settings links to it.shep settings flags [enable|disable <flag>]does the same from the CLI.1b681a2b4e7420renumbers the spec to 135: the telemetry and unified-decisions workstreams took 133 and 134.Why
Implements
specs/135-review-cleanup-cuts/, from the "Where Shep Is Today and What to Cut" section ofdocs/competitors/t3code.md.Screenshots / Recording
I checked the feature-flags view at desktop and phone width in the running app with
pnpm dev:weband Playwright. Turningspacesoff removed the Spaces link from the sidebar and made/spacesreturn 404; turning it back on restored both. (The screenshots are local to the session; I can attach them if needed.)Testing
Local runs, on the merge of
mainatd97bc6f(telemetry #923, decisions #922/#924):pnpm generatepnpm tsp:compilepnpm lint,pnpm format:checkpnpm typecheckpnpm test:unitpnpm test:intpnpm check:storiespnpm build:releasepnpm build:storybookNew tests:
shep settings flagsrequireFeaturePageStories added: FeatureFlagsList, FeatureFlagsPageClient, ProviderList, CloudProviderIcons.
SettingsRows(and its stories) now come frommain; this PR keeps only the row's flex basis so switches stay beside long descriptions.Notes for the reviewer
recaps/files already show (zero events), since recognition is still recorded by hand (see CONTRIBUTING). The stale-issues job reads GitHub and works as is.mainholds 166 (agent-question decisions), 167 (decision timeout) and 168 (telemetry).response.finished(), which hung for 60s in CI while the re-rendered page streamed.main's empty-config-file approach; the pty teardown tolerates a lingering ConPTY host (4d1b86f).shep security enforcekeeps its name. Moving it undershep aspmwould have broken existing CI scripts.Checklist
pnpm lintpassespnpm format:checkpassespnpm typecheckpassespnpm test:unitandpnpm test:intpasspnpm buildsucceedspnpm build:storybooksucceeds and every new component has a colocated.stories.tsxpnpm tsp:compileran andoutput.tsis committeddomain/orapplication/file imports frominfrastructure/feat/fixfor user-visible changesπ€ Generated with Claude Code
https://claude.ai/code/session_01TxtN2VcWzg6NTCLj4DbmfL